/**
 * cpair header
 * 
 * @author strlst <e11907086@student.tuwien.ac.at>
 * @date 2020-12-01
 * @brief contains macro definitions and data structures used throughout the module
 */

#ifndef CPAIR_H
#define CPAIR_H

#include <errno.h>
#include <float.h>
#include <getopt.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/wait.h>

/* two doubles and a whitespace should not take more than 1+2*64 characters */
/* (next power of 2) - 1 to be safe */
#define BUF_SIZE (256)
#define POINTS   (2)
#define INVALID  (DBL_MAX)

/**
 * @brief point structure to store two double values
 */
typedef struct {
    double x; /**< x component */
    double y; /**< y component */
} point;

/**
 * @brief pair structure to store two points
 */
typedef struct {
    point a; /**< 1st point */
    point b; /**< 2nd point */
} pair;

/**
 * @brief takes a heap of arguments to compute the clostest pair of points
 * @details uses fork to recursively compute the result, exits with EXIT_FAILURE on error
 * @param argv argument vector, used for error handling output
 * @param line string buffer, because find_closest_pair needs to process lines and the callee assuredly has to as well
 * @param points array of points
 * @param n number of points
 */
void find_closest_pair(char**, char*, point*, size_t);

/**
 * @brief exits with specified exit_code after printing a specified message
 * @details message assumes a format specifier for the string 'program' parameter, message can also include an additional %s format specifier to print ERRNO messages
 * @param message string containing the message to be printed
 * @param program string containing the program name
 * @param exit_code exit code
 */
void die(char*, char*, int);

/**
 * @brief auxiliary method used to calculate euclidean distance between two points
 * @details makes use of double precision and math.h
 * @param a first point
 * @param b second point
 * @return EXIT_FAILURE on failure, EXIT_SUCCESS on success
 */
double euclidean_distance(point, point);

/**
 * @brief auxiliary method used take input values from child processes
 * @details blocks until either EOF has been signalled or two lines of values have been supplied, gracefully handles both cases
 * @param line char buffer used for processing
 * @param stream FILE pointer pointing to a file descriptor to be read from
 * @return pair of points, all values have DBL_MAX if an error has occurred
 */
pair try_read(char*, FILE*);

/**
 * @brief briefly checks if any point has DBL_MAX set on any of its coordinates
 * @details DBL_MAX is by convention used as an invalid value, because DBL_MAX is highly unlikely to occur in practice
 * @param point to check
 * @return ret integer boolean value that hints at whether the point is valid or not
 */
int is_valid(point);

/**
 * @brief auxiliary method used integrate results of child processes as well as parent process itself
 * @details the whole method itself may appear messy, but it complies with the algorithm which calls for some of these complicated structures
 * @param p1 pair of points from first child process
 * @param p2 pair of points from second child process
 * @param p3 pair of points from third child process
 * @param p3_dist euclidean distance for p3, because that value is presumaly already precomputed
 * @return pair of points with the smallest euclidean distance in the whole set
 */
pair get_best_contender(pair, pair, pair, double);

/**
 * @brief auxiliary method used to sort vectors of points
 * @details because of the recursive nature of the cpair algorithm, this method is often going to be called unnecessarily, so at the very least an attempt was made to not let the quadratic runtime apply every time, this method checks if the values are already sorted, swaps values in place
 * @param points vector of points
 * @param n number of points
 */
void bubblesort(point*, int);

/**
 * @brief auxiliary method used to print parent and child processes
 * @details does not display intermediary results, only the top-most layer of recursion
 * @param n number of points
 * @param points vector of points
 * @param n_bin1 number of points in the first bin
 * @param points_bin1 vector of points in the first bin
 * @param n_bin2 number of points in the second bin
 * @param points_bin2 vector of points in the second bin
 */
void print_tree(int, point*, int, point*, int, point*);

#endif
